package main

import (
	"fmt"
	"time"
)

func main() {
	//base()
	//useChannle()
	//useChannleTow()
	useChanSleep()
}

/*
*
channel基础
*/
func base() {
	cha := channel()
	fmt.Printf("数据类型是： %T\n", cha)
	channle := newChannel()
	fmt.Printf("数据类型是： %T\n", channle)
	fmt.Printf("channle管道内存地址%T, %p\n", &channle, &channle)
	fmt.Printf("channle管道内存地址%T, %p\n", channle, channle)
	a := channelType(channle)
	fmt.Printf("a管道内存地址%T, %p\n", &a, &a)
	fmt.Printf("a管道内存地址%T, %p\n", a, a)
}

/*
*
通道的声明
//声明通道
var 通道名 chan 数据类型
//创建通道：如果通道为nil(就是不存在)，就需要先创建通道
通道名 = make(chan 数据类型)
*/
func channel() *chan int {
	var a chan int
	if a == nil {
		fmt.Println("channel 是 nil 的, 不能使用，需要先创建通道。。")
		a = make(chan int)
		fmt.Printf("数据类型是： %T", a)
	}
	return &a
	/**
	输出
	channel 是 nil 的, 不能使用，需要先创建通道。。
	数据类型是： chan int
	*/
}

func newChannel() chan int {
	return make(chan int)
}

func channelType(cha chan int) chan int {
	fmt.Printf("cha管道内存地址%T, %p\n", &cha, &cha)
	fmt.Printf("cha管道内存地址%T, %p\n", cha, cha)
	return cha
}

/*
*
channel的使用
*/
func useChannle() {
	a := make(chan int)
	go func() {
		fmt.Println("子goroutine执行。。。")
		time.Sleep(3 * time.Second)
		for i := 0; i < 10; i++ {
			a <- i
		}

	}()
	a <- 2
	data := <-a // read from channel a
	fmt.Println(data)
}

/**
在下面的程序中，我们先创建了一个chan bool通道。然后启动了一条子Goroutine，并循环打印10个数字。
然后我们向通道ch1中写入输入true。然后在主goroutine中，我们从ch1中读取数据。这一行代码是阻塞的，这意味着在子Goroutine将数据写入到该通道之前，
主goroutine将不会执行到下一行代码。因此，我们可以通过channel实现子goroutine和主goroutine之间的通信。当子goroutine执行完毕前，
主goroutine会因为读取ch1中的数据而阻塞。从而保证了子goroutine会先执行完毕。
这就消除了对时间的需求。在之前的程序中，我们要么让主goroutine进入睡眠，以防止主要的Goroutine退出。要么通过WaitGroup来保证子goroutine先执行完毕，主goroutine才结束。
*/

func useChannleTow() {
	var ch1 chan bool       //声明，没有创建
	fmt.Println(ch1)        //<nil>
	fmt.Printf("%T\n", ch1) //chan bool
	ch1 = make(chan bool)   //0xc0000a4000,是引用类型的数据
	fmt.Println(ch1)

	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println("子goroutine中，i：", i)
		}
		// 循环结束后，向通道中写数据，表示要结束了。。
		ch1 <- true

		fmt.Println("结束。。")

	}()

	data := <-ch1 // 从ch1通道中读取数据
	fmt.Println("data-->", data)
	fmt.Println("main。。over。。。。")

	/**
	输出
	<nil>
	chan bool
	0xc000010720
	子goroutine中，i： 0
	子goroutine中，i： 1
	子goroutine中，i： 2
	子goroutine中，i： 3
	子goroutine中，i： 4
	子goroutine中，i： 5
	子goroutine中，i： 6
	子goroutine中，i： 7
	子goroutine中，i： 8
	子goroutine中，i： 9
	结束。。
	data--> true
	main。。over。。。。
	*/
}

func useChanSleep() {
	ch1 := make(chan int)
	done := make(chan bool) // 通道
	go func() {
		fmt.Println("子goroutine执行。。。")
		time.Sleep(3 * time.Second)
		data := <-ch1 // 从通道中读取数据
		fmt.Println("data：", data)
		done <- true
	}()
	// 向通道中写数据。。
	time.Sleep(5 * time.Second)
	ch1 <- 100

	<-done
	fmt.Println("main。。over")
}
